# description property
from weakref import WeakKeyDictionary

class Homework(object):
    def __init__(self):
        self._grade = 0

    @property
    def grade(self):
        return self._grade
    
    @grade.setter
    def grade(self, value):
        if not (0 <= value <= 100):
            raise ValueError('Crade must be between 0 and 100')
        self._grade = value

# description class
class Grade(object):
    def __init__(self):
        self._value = WeakKeyDictionary()
    
    def __get__(self, instance, instance_type):
        if instance is None: 
            return self
        
        return self._value.get(instance, 0) # get value by different instance
    
    def __set__(self, instance, value):
        if not (0 <= value <= 100):
            raise ValueError('Crade must be between 0 and 100')
        self._value[instance] = value
    
class Exam(object):
    math_grade = Grade()
    writing_grade = Grade()
    

first = Exam()
second = Exam()

first.math_grade = 10
second.math_grade = 20
first.writing_grade = 90
second.writing_grade = 80
print(first.math_grade, ',', first.writing_grade)
print(second.math_grade, ',', second.writing_grade)
